package com.ultrapower.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义Ribbon轮询算法的接口实现类,
 * 算法概述:
 *          利用rest请求访问数 % 服务集群的所有实例,就是对应的指定索引的服务下标,rest服务接口计数是从1开始.
 * @author shiwenxi
 * @date 2022-05-24 19:26
 */
@Component
public class MyLB implements LoadBalancer{

	/**
	 * 便于多线程情况下的操作,原子整型,每次服务重启的时候就是保证它为0开始
	 */
	private AtomicInteger atomicInteger = new AtomicInteger(0);

	/**
	 * 自旋锁,将对应的数字进行比较指到比较完成为止,主要是为了防止多线程访问的时候出现数据的错误
	 * @return return
	 */
	public final int getAndIncrement(){
		int current;
		int next;
		do {
			//获取当前的原子整型
			current = atomicInteger.get();
			 //0  获取当前的主内存中的数据
			//如果rest请求数越界,那么将服务器请求置为初始话0,否则一次+1
			next = current >= 2147483647 ? 0 : current + 1;
			//下一次的数据需要++,如果数据越界,直接重置为默认值0
		}while(!this.atomicInteger.compareAndSet(current,next));
		//判断当前值与期望值是否已经一致(工作区内存与主内存一致),CAS + 自旋锁
		System.out.println("***************next:" + next);
		//next就是rest接口访问的第几次.
		return next;
	}

	/**
	 * 获取服务实例的接口
	 *
	 * @param serviceInstances 传入的所有的服务实例的集合
	 * @return 指定的服务实例
	 */
	@Override
	public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
		int index = getAndIncrement() % serviceInstances.size();
		//得到需要运行服务的下标索引
		return serviceInstances.get(index);
	}
}
